//------------------------------------------------------------------------------
// X2D Game Engine
// Copyright (C) 2006-2007 Janusz Kowalski
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
//------------------------------------------------------------------------------

#include <cassert>

#include "x2d_Form.h"
#include "SDL.h"

// Z zewnatrz mapa zachowuje sie jak dwuwymiarowa tablica o kilku planach,
// do ktorej dostep uzyskuje sie poprzez funkcje i ktora zwraca formId
// obiektow. Wewnetrznie moze byc przechowywana w postaci tablicy, generowana
// losowo, lub reprezentowana w dowolny inny sposob.

// Mapa nie ma danych wymiarów. Jest "nieskonczona".

#ifndef X2D_MAP_H
#define X2D_MAP_H

namespace x2d {

// Type of the map field.
typedef Uint32 MapFieldT;

// Number of map layers (map depth).
const int MAP_D = 4;

const int MAP_MAX_D = MAP_D;

class Map {
  public:
    // Type of map field attributes.
    typedef Uint32 AttrT;
    // Attributes of map fields.
    static const AttrT ATTR_SHR = 0x01;   // Shift right.
    static const AttrT ATTR_SHL = 0x02;   // Shift left.
    static const AttrT ATTR_SHD = 0x04;   // Shift down.
    static const AttrT ATTR_SHU = 0x08;   // Shift up.
  private:
    MapFieldT *data[MAP_D];
    int w;
    int h;
  public:
    bool show_guidelines;
  private:
    void passiveEvent(int x, int y, int plane, int formID);
    void passiveInit(int x, int y, int plane);
  public:
    Map(int w, int h);
    
    ~Map();
    
    // Return width of the map
    inline int getW() const {return w;};
    
    // Return height of the map
    inline int getH() const {return h;};
    
    // Return depth of the map.
    inline int getD() const {return MAP_D;}
    
    void newMap(int w, int h);
    void freeMap();
    
    // Clear map.
    void clear();
    void currentPlane(int n);
    void getRect();
    bool inside(int x,int y) const;
    
    // Get the value of a map field on the given plane. This value includes
    // all the data.
    inline MapFieldT get(int x, int y, int p) const {
      if(inside(x,y)) return *(data[p]+y*w+x);
      else if (show_guidelines && (x==-1 || x==w || y==-1 || y==h)) return FormId_Wall_1;
      else return 0;
    }
    
    // Set the value of a map field on a given plane.
    void set(int x, int y, int plane, MapFieldT xid);
    
    inline int getForm(int x, int y, int z) {
      return (get(x,y,z) & 0x00FFFFFF);
    }
    
    inline AttrT getAttr(int x, int y, int z) {
      return (get(x,y,z) & 0xFF000000) >> 24;
    }
    
    // Returns Vertical/Horizontal shift, that should be added to the position
    // of a map object,
    int getVShift(int x, int y, int z);
    int getHShift(int x, int y, int z);
    
    void setForm(int x, int y, int z, int formId);
    
    void setAttr(int x, int y, int z, AttrT attr);
    
    // Save map to file.
    void save(const char *path);
    
    // Load map from file.
    void load(const char *path);
};

} /* namespace x2d */

#endif
